--
-- Author: shunguo.chen
-- Date: 2018-03-07 16:46:25
--
-- ChessController	星空谜棋控制器
--

local Armature = app:getClass("Armature")

local ChessView = import("..views.ChessView")
local ChessEventView = import("..views.ChessEventView")
local ChessHeroView = import("..views.ChessHeroView")
local ChessReadyView = import("..views.ChessReadyView")
local ChessNpcView = import("..views.ChessNpcView")
local ChessResultEfcView = import("..views.ChessResultEfcView")

local ChessRender = import("..views.renders.ChessRender")
local ChessTipRender = import("..views.renders.ChessTipRender")

local ChessAction = import("..models.ChessAction")

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ControllerBase)

function ClassRef:ctor(params)
	self.super.ctor(self, params)

end

function ClassRef:init()
	self._model = app:getInst("ChessModel")

	-- 战斗位置
	self._battlePosX = 0

	--我／对手 的角色 地图上格子
	self._myActor = nil
	self._enemyActor = nil
	self._renders = nil

	-- 我／对手 当前所在格子
	self._myRender = nil
	self._enemyRender = nil

	-- 玩家移动的act
	self._moveAct = nil

	-- 地图计时act和时间
	self._timeAct = nil

	-- 选中脚下动画, 包含我的和对手的
	self._selectArmatures = {}

	-- 谜棋格子tip
	self._chessTip = nil

	-- 角色是否在地图移动中
	self._isInMove = false
end

function ClassRef:removeListeners()
	self.super.removeListeners(self)
end

function ClassRef:listEvent()
	return {
		"onMapChanged",
		"onReconnectSuccessed"
	}
end

function ClassRef:onEvent(eventName, ...)
	local data = ...
	if eventName == "onMapChanged" then
		-- data = 是否刚刚进入游戏, 非刚刚进入游戏，需要通知服务器开始星空谜棋
		if not data then
			self._model:reqStartChess()
		end

		-- 移除地图touch事件，停止自动寻路
		if self._model:isChessMap() then
			local launchCtl = app:getLaunchCtl()
			launchCtl:removeTouchLayer()
			launchCtl:addChessTouchLayer()

			-- 模拟点击停止，其他的方法没找到
			launchCtl:endCharacterMove()
		end

		-- test
		-- if self._model:isChessMap() then
		-- 	self:openView()
		-- 	self:refreshMap()
		-- end
	elseif eventName == "onReconnectSuccessed" then
		if self._model:isChessMap() then
			self:onReconnect()
		end
	end
end

-- 打开谜棋操作界面
function ClassRef:openView(data)
	if cc.isDead(self._view) then
		self._view = ChessView.new(app.mvc.VIEWTYPE_NORMAL)
		self._view:onCloseView(handler(self, self.closeView))
		self._view:onClearView(handler(self, self.clearView))
		self._view:onOperate(handler(self, self.onOperate))
		self:addChild(self._view, data)
	end

	UIHandler:getSystemUi():removeAllUI()
	UIHandler:hideDesktop()

	app:sendMsg("IMSimpleController", "showView", Enums.IMSimpleShowType.msgs)
	app:sendMsg("CosplayController", "closeView")

	self._view:show()
	local chessInfo = self._model:getChessInfo()
	self._view:refresh(chessInfo)

	if not chessInfo:isStart() then
		-- 回合还没开始，需要打开vs宣战界面
		app:sendMsg("PvpController", "openVSView", chessInfo:getVSInfos())
	else
		-- 回合已开始了，需要恢复一些状态
		if chessInfo:isMove() then
			-- 如果在move状态, 我和机器人直接发actionOver
			if chessInfo:isMyAction() or chessInfo:isRobotAction() then
				self._model:reqActionOver("MoveAnim")
			end
		end
	end
end
function ClassRef:closeView(data)
	if self._view then
		self:removeChild(self._view, data)
		UIHandler:showDesktop()
	end
end
function ClassRef:clearView()
	if self._view then
		self._view = nil
		self:closeNpcView()
		self:closeReadyView()
	end
end

-- 刷新地图上的棋盘
function ClassRef:refreshMap()
	local info = self._model:getChessInfo()

	-- 移除地图touch事件
	-- app:getLaunchCtl():removeTouchLayer()

	if not self._renders then
		local tip = self:getChessTip()
		local myPos = info.myPlayer.pos
		local cells = info.cells
		local map = MapManager:getMap()
		local pathNodes = map:getMiddlePathNodes()
		local parent = pathNodes[1]:getParent()
		local renders = {}
		for i,node in ipairs(pathNodes) do
			local render = ChessRender.create()
			local data = cells[i]
			render:setData(data)
			local x, y = node:getPosition()
			render:setPosition(x, y)
			render:setPosX(x)
			if data then
				render:setTouchTip(tip, function()
					return not self._isInMove
				end)
			end
			parent:addChild(render)
			renders[i] = render
			if i == Constant.CHESS_MAX_CELL then break end
		end
		self._renders = renders
		self._battlePosX = pathNodes[#pathNodes - 1]:getPositionX()

		self._myActor, self._enemyActor = FieldManager:createChessCharacter(info:getBaseInfos())
		self._myActor:faceToRight()
		self._myActor:setTitle("")
		self._myActor:setGuildName("")
		self._enemyActor:faceToRight()
		self._enemyActor:setTitle("")
		self._enemyActor:setGuildName("")

		map:setExitCB(handler(self, self._mapClear))

		-- print("self._battlePosX", self._battlePosX, #pathNodes)
	end

	self:_mapRoundChange(true)
	self:_mapStatusUpdate()

	-- 战斗中，需要强移
	if info:isBattle() then
		self:mapBattle()
	end
end

-- 打开英雄抉择界面
-- select = ChessSelect
-- info = ChessInfo
function ClassRef:openHeroView(select, info)
	local view = ChessHeroView.new()
	view:onCloseView(function(sender)
		UIHandler:removePopupUiByKey(sender:getViewName())
	end)
	view:onOperate(function(op, param)
			if op == "selectHero" then
				self._model:reqSelect(param)
			elseif op == "openRole" then
				-- 打开角色详情界面
				app:sendMsg("CosplayController", "openBookView", param)
			end
		end)
	view:refresh(select, info)
	UIHandler:addPopupUi(view, view:getViewName())
	view:show()
end

-- 打开事件抉择界面
-- select = ChessSelect
-- info = ChessInfo
function ClassRef:openEventView(select, info)
	local view = ChessEventView.new()
	view:onCloseView(function(sender)
		UIHandler:removePopupUiByKey(sender:getViewName())
	end)
	view:onOperate(function(op, param)
			if op == "selectEvent" then
				self._model:reqSelect(param)
			end
		end)
	view:refresh(select, info)
	UIHandler:addPopupUi(view, view:getViewName())
	view:show()
end

-- 打开战前准备界面
-- player = ChessPlayer
-- newRoleId = 新获得的roleId
function ClassRef:openReadyView(player, newRoleId)
	local view = self:getReadyView()
	if not view then
		view = ChessReadyView.new()
		view:onCloseView(function(sender)
			UIHandler:removePopupUiByKey(sender:getViewName())
		end)
		UIHandler:addPopupUi(view, view:getViewName())
	end
	view:refresh(player, newRoleId)
	view:show()
end
-- 获得已有的战前准备界面
function ClassRef:getReadyView()
	return UIHandler:getPopupUi():isCreateUi(ChessReadyView:getViewName())
end
-- 关闭战前准备界面
function ClassRef:closeReadyView()
	UIHandler:removePopupUiByKey(ChessReadyView:getViewName())
end

-- 打开npc界面
-- msg = npc说话内容
-- time = 持续时间
-- cb = 回调
function ClassRef:showNpcView(msg, time, cb)
	local view = self:getNpcView()
	if not view then
		view = ChessNpcView.new()
		UIHandler:addPopupUi(view, view:getViewName())
	end
	view:refresh(msg, time, cb)
	view:show()
end
-- 获得已有的战前准备界面
function ClassRef:getNpcView()
	return UIHandler:getPopupUi():isCreateUi(ChessNpcView:getViewName())
end
function ClassRef:hideNpcView()
	local view = self:getNpcView()
	if view then
		view:hide()
	end
end
function ClassRef:closeNpcView()
	UIHandler:removePopupUiByKey(ChessNpcView:getViewName())
end

-- 获得地图格子tip，只有一个对象，比self._view高一层级，谜棋结束时移除
function ClassRef:getChessTip()
	local tip = self._chessTip
	if not tip then
		tip = ChessTipRender.create()
		tip:setVisible(false)
		app:getLaunchCtl():addChild(tip, SceneZOrder.desktopZOrder + 1)
		self._chessTip = tip
	end
	return tip
end
-- 隐藏地图格子tip
function ClassRef:hideChessTip()
	if self._chessTip then
		self._chessTip:setVisible(false)
	end
end
-- 删除地图格子tip
function ClassRef:removeChessTip()
	if not cc.isDead(self._chessTip) then
		self._chessTip:removeFromParent()
	end
	self._chessTip = nil
end

------------------------------------------------------------
-- 重连成功，重新拉去数据
function ClassRef:onReconnect()
	-- print("ChessController.onReconnect")
	app:sendMsg("WorldModel", "C2S_RecoveryGameInfo")
end

-- 回合开始
function ClassRef:onRoundStart(info)
	if not self:isViewAlive() then return end

	self:closeReadyView()
	self:showNpcView(info:getRoundMsg(), 2, function()
		-- 回合开始，如果有本回合buff，要有所表现
		local player = info:getCurPlayer()
		if player:hasGameBuff() then
			-- 1下回合投掷点数
			-- 2掷出点数后移动
			-- 3下回合行动倍率
			-- 4下回合暂停
			local isMyRound = info:isMyRound()
			local buffTp, msg = player:getGameBuffData(isMyRound)
			self:showNpcView(msg, 2, function()
					--类型=4，表现完成需要发送actionOver，通知服务器
					if buffTp == 4 then
						self._model:reqActionOver("ActionAnim")
					end
				end)
		end
	end)
	self._view:roundChange()

	-- refresh map
	self:_mapRoundChange()
end

-- 状态改变
function ClassRef:onStatusUpdate()
	if not self:isViewAlive() then return end

	self._view:statusUpdate()
	self:_mapStatusUpdate()
end

-- 播放roll点动画
function ClassRef:onRollResult(msg)
	if not self:isViewAlive() then return end
	local tp = (msg.type == "GOLDEN") and 1 or 2
	self._view:playRollAction(msg.finalNum, tp)
end

-- 玩家移动
function ClassRef:onPlayerMove(startPos)
	if not self:isViewAlive() then return end
	self._view:playerMove(startPos)
	self:_mapPlayerMove(startPos)
end

-- 玩家抉择
-- select = ChessSelect
function ClassRef:onPlayerSelect(select)
	if not self:isViewAlive() then return end

	local info = self._model:getChessInfo()
	if info:isMyAction() then
		if select:isRoleSelect() then
			self:openHeroView(select, info)
		else
			self:openEventView(select, info)
		end
	else
		-- display.pushToast("对手 抉择中...")
	end
end

-- 事件触发
function ClassRef:onPlayerAction(msg)
	if not self:isViewAlive() then return end

	local info = self._model:getChessInfo()
	local action = ChessAction.new(msg.actionID)

	local isMe = info:isMe(msg.uid)
	local data = action:getTipData(isMe)
	self._view:addActionTip(data)

	local npcShowTime = action:npcShowTime()

	if npcShowTime > 0 then
		self:showNpcView(action:getDesc(isMe), npcShowTime, function()
				-- 1. 我的事件，发actionOver 2. 机器人的事件，发actionOver
				if isMe or msg.uid < 0 then
					self._model:reqActionOver("ActionAnim")
				end
			end)
	end

	if action:isBattle() then
		self:mapBattle()
	end
end

-- 自己信息更新
function ClassRef:onChessOp(msg)
	if not self:isViewAlive() then return end

	local tp = msg.type
	if tp == "ROLEDATA" or tp == "BUFFDATA" then
		local info = self._model:getChessInfo()
		local op = msg.op
		if tp == "ROLEDATA" and op == "ADD" then
			-- 获得新的role，需要马上打开战前准备界面
			self:openReadyView(info.myPlayer, msg.ids[1])
		elseif self:getReadyView() then
			-- 战前准备界面存在，刷新数据
			self:openReadyView(info.myPlayer)
		end
	else
		self._view:refreshMyInfo(tp)
	end
end

-- 星空谜棋战斗结果
function ClassRef:onChessBattleResult(msg)
	local str = msg.won and L("lua_code_text_113") or L("lua_code_text_221")
	display.pushToast(str)

	self:openView()
	self:refreshMap()
end

-- 星空谜棋结果
function ClassRef:onChessResult(msg)
	self:_mapClear()
	self:removeChessTip()

	-- loading中就失败，说明是超时导致的失败
	if app:sendMsg("PvpModel", "isInPvpLoading") and msg.result == "LOSE"then
		-- 模拟关闭loading界面并调用C2S_BackToLastMap
		display.pushToast(L("OtherPlayerRun"))
		app:sendMsg("PvpModel", "S2C_PVPLoadingClose")
		app.session:request("pb_map.C2S_BackToLastMap",{})
		return 
	end

	local reason
	local tp = msg.overType
	if msg.result == "WIN" then
		if tp == "PLAYERTIMEOVER" then
			reason = "starChessWinByTime"
		elseif tp == "PLAYERWITHOUTDICE" then
			reason = "starChessWinByDice"
		elseif tp == "PLAYERONENDCELL" then
			reason = "starChessWinByReachEnd"
		end
	else
		if tp == "PLAYERTIMEOVER" then
			reason = "starChessFailedByTime"
		elseif tp == "PLAYERWITHOUTDICE" then
			reason = "starChessFailedByDice"
		elseif tp == "PLAYERONENDCELL" then
			reason = "starChessFailedByReachEnd"
		elseif tp == "GAMEDEADLINE" then
			reason = "starChessFailedByTime"
		elseif tp == "PLAYERESC" then
			reason = L("lua_code_text_345")
		end
	end

	if not reason then
		reason = L("lua_code_text_459")
	end
	reason = L(reason)

	local view = ChessResultEfcView.new()
	view:onCloseView(function(sender)
		UIHandler:removePopupUiByKey(sender:getViewName())

		-- local funcName = msg.result == "WIN" and "openWinView" or "openFailView"
		-- app:sendMsg("PvpController", funcName, nil, function()
		-- 	self._model:reqBackToMap()

		-- 	MapManager:setChangeMapOverCB(function()
		-- 		self:closeView()
		-- 		app:sendMsg("PvpController", "openView")
		-- 	end)
		-- end, reason)

		-- 胜利是通过服务器消息走的 NewActivityDungeonsController:openSuccessView
		-- 只有非胜利才走此处逻辑
		if msg.result ~= "WIN" then
			local params = { id = Enums.TeamTarget.chess, reason = reason, open = true }
			app:sendMsg("NewActivityDungeonsController", "openFailView", params)
		end
	end)
	view:refresh(msg.result == "WIN")
	UIHandler:addPopupUi(view, view:getViewName())
	view:show()
end

-- 清理谜棋状态
function ClassRef:_mapClear()
	-- print("ChessController._mapClear")
	self:_removeTimeAct()
	self:_removeMoveAct()

	self._battlePosX = 0
	self._myActor = nil
	self._enemyActor = nil
	self._renders = nil
	self._myRender = nil
	self._enemyRender = nil

	self._curActionActor = nil

	self._selectArmatures = {}
end

------------------------------------------------------------
function ClassRef:_comfirmEscape()
	local msg = L("lua_code_text_444")
	local confirmDialog = app.mvc.DialogBase.new(msg,
		function()
			self._model:reqEscape()
		end,
		function()

		end)
	confirmDialog:setConfirmText(L("lua_code_text_209"))
	UIHandler:addPopupUi(confirmDialog)
end

function ClassRef:onOperate(op, param)
	-- print("ChessController:onOperate op = " .. op)
	if op == "openReady" then
		local info = self._model:getChessInfo()
		self:openReadyView(info.myPlayer)
	elseif op == "openSet" then
		-- 打开设置

	elseif op == "escape" then
		self:_comfirmEscape()
	elseif op == "roll" then
		self._model:reqRoll(0)
	elseif op == "rollGold" then
		self._model:reqRoll(param)
	elseif op == "actionOver" then
		self._model:reqActionOver(param)
	end
end

-- 地图回合切换
-- isInit 是第一次触发
function ClassRef:_mapRoundChange(isInit)
	self:hideChessTip()

	local info = self._model:getChessInfo()
	local myPlayer = info.myPlayer
	local enemyPlayer = info.enemyPlayer
	local isMyRound = info:isMyRound()

	self._myRender = self._renders[myPlayer.pos]
	self._enemyRender = self._renders[enemyPlayer.pos]

	if isMyRound then
		self:_addSelectArmature(not isMyRound)
		self:_addSelectArmature(isMyRound)
	else
		self:_addSelectArmature(isMyRound)
		self:_addSelectArmature(not isMyRound)
	end

	local myPosX = self._myRender:getPosX()
	local enemyPosX = self._enemyRender:getPosX()
	self._myActor:showLocationX(myPosX)
	self._enemyActor:showLocationX(enemyPosX)
	local curActor = isMyRound and self._myActor or self._enemyActor
	if not isInit and math.abs(myPosX - enemyPosX) < display.width then
		-- 距离小于一屏，移动过去
		MapManager:setFocusCharacterNotInit({character=curActor})
	else
		-- 距离大于一屏，需要init
		MapManager:setFocusCharacterForInit({character=curActor})
	end

	-- 刷新GameBuff
	if myPlayer:hasGameBuff() then
		local msg = myPlayer:getGameBuffMsg(isMyRound)
		self._myActor:setGuildName(msg, true)
	else
		self._myActor:setGuildName("")
	end
	if enemyPlayer:hasGameBuff() then
		local msg = enemyPlayer:getGameBuffMsg(not isMyRound)
		self._enemyActor:setGuildName(msg, true)
	else
		self._enemyActor:setGuildName("")
	end
end

-- 地图状态更新，主要刷新角色头上时间
function ClassRef:_mapStatusUpdate()
	local info = self._model:getChessInfo()

	self:_removeTimeAct()
	if info:needCountTime() then
		local isMyAction = info:isMyAction()
		if isMyAction then
			self._curActionActor = self._myActor
			self._enemyActor:setTitle("")
		else
			self._curActionActor = self._enemyActor
			self._myActor:setTitle("")
		end

		self:_startTimeAct()
	else
		self._myActor:setTitle("")
		self._enemyActor:setTitle("")
	end
end

function ClassRef:_startTimeAct()
	local info = self._model:getChessInfo()
	local remainTime = info and info:getRemainTime() or 0

	if remainTime <= 0 then
		self._curActionActor:setTitle("")
		self._curActionActor = nil
		self._timeAct = nil
		return
	end

	if info and info:needCountTime() then
		local str = info:getCountTimeStr()
		self._curActionActor:setTitle(string.format(str, remainTime))
		self._timeAct = self._myActor:performWithDelay(function()
				self:_startTimeAct()
			end, 1)
	end
end
function ClassRef:_removeTimeAct()
	if self._timeAct and not cc.isDead(self._myActor) then
		self._myActor:stopAction(self._timeAct)
	end
	self._timeAct = nil
end

-- 添加脚下的圈圈
-- isMe = true/false 是我自己
function ClassRef:_addSelectArmature(isMe)
	local name = isMe and "lanquan" or "hongquan"
	local armature = self._selectArmatures[name]
	if not self._selectArmatures[name] then
		local params = {
			armatureName = name,
			path = Res.ChessSelectEfcPath
		}
		armature = Armature.create(params)
		self._selectArmatures[name] = armature
	end

	-- 双方在同一位置，只会显示一个，另外一个需要隐藏
	if self._myRender == self._enemyRender then
		local otherName = (not isMe) and "lanquan" or "hongquan"
		if self._selectArmatures[otherName] then
			self._selectArmatures[otherName]:setVisible(false)
		end
	end

	local render = isMe and self._myRender or self._enemyRender
	local parent = armature:getParent()
	if parent then
		if parent ~= render then
			armature:removeFromParent(false)
			render:addSelectArmature(armature)
		end
	else
		render:addSelectArmature(armature)
	end

	armature:setVisible(true)
	armature:playDefault(0)
end

function ClassRef:_hideSelectArmature(isMe)
	local name = isMe and "lanquan" or "hongquan"
	if self._selectArmatures[name] then
		self._selectArmatures[name]:setVisible(false)
	end
end


-- 地图角色移动
function ClassRef:_mapPlayerMove(startPos)
	self:hideChessTip()

	local info = self._model:getChessInfo()
	local curActionPlayer = info:getCurActionPlayer()
	local curNoActionPlayer = info:getCurNoActionPlayer()
	local isMyAction = info:isMyAction()

	-- 取消当前action选择, 需要考虑双方在同一位置
	if self._myRender == self._enemyRender then
		self:_addSelectArmature(not isMyAction)
	else
		self:_hideSelectArmature(isMyAction)
	end

	-- 开始render
	local curRender = self._renders[startPos]
	local curPosX = curRender:getPosX()
	local curOppPosX = self._renders[curNoActionPlayer.pos]:getPosX()

	-- 目标render
	local tarPos = curActionPlayer.pos
	local factor = (tarPos - startPos) / math.abs(tarPos - startPos)
	local tarRender = self._renders[tarPos]
	local tarPosX = tarRender:getPosX()
	self:_playTargetAction(tarRender, isMyAction)

	local curActor = isMyAction and self._myActor or self._enemyActor
	if math.abs(curPosX - curOppPosX) < display.width then
		MapManager:setFocusCharacterNotInit({character=curActor})
	else
		MapManager:setFocusCharacterForInit({character=curActor})
	end

	self._isInMove = true
	curActor:playChessAction(factor == 1)
	curActor:setTargetX(tarPosX, function()
			self._isInMove = false

			-- 停止箭头动画
			curActor:stopChessAction()
			-- 刷新目标格子状态
			tarRender:refresh()
			-- 停止目标动画，如果有事件，并且是自己的，播放触发动画
			local data = tarRender:getData()
			if data and isMyAction then
				self:_stopTargetAction(tarRender, function()
					-- 我的动作／机器人 发送actionOver
					if isMyAction or info:isRobotAction() then
						self._model:reqActionOver("MoveAnim")
					end
				end)
			else
				self:_stopTargetAction()
				-- 我的动作／机器人 发送actionOver
				if isMyAction or info:isRobotAction() then
					self._model:reqActionOver("MoveAnim")
				end
			end

			if isMyAction then
				self._myRender = tarRender
			else
				self._enemyRender = tarRender
			end
			self:_addSelectArmature(isMyAction)
		end)

	-- 路径上的render特殊显示
	local pathRenders = {}
	for i=startPos+factor,tarPos-factor,factor do
		local render = self._renders[i]
		render:setIsPath(true)
		pathRenders[#pathRenders + 1] = render
	end

	-- 检测是否到达路径上的render
	local halfWidth = curRender:getHalfWidth()
	self:_removeMoveAct()
	if #pathRenders > 0 then
		local action = self._myActor:schedule(function()
				if #pathRenders > 0 then
					local posX = curActor:getPositionX()
					local render = pathRenders[1]
					local renderX = render:getPositionX()
					if math.abs(posX - renderX) <= halfWidth then
						-- todo 移动入下一个render，设置render状态
						render:setIsPath(false)
						table.remove(pathRenders, 1)
					end
				else
					self:_removeMoveAct()
				end
			end, 0.2)
		self._moveAct = action
	end
end

function ClassRef:_removeMoveAct()
	if self._moveAct and not cc.isDead(self._myActor) then
		self._myActor:stopAction(self._moveAct)
	end
	self._moveAct = nil
end

function ClassRef:_playTargetAction(render, isMe)
	local x, y = render:getPosition()
	local map = MapManager:getMap()
	map:playChessAction(x, y, isMe)
end
function ClassRef:_stopTargetAction(render, cb)
	local map = MapManager:getMap()
	map:stopChessAction(render, cb)
end

-- 触发战斗，需要移动玩家到战场
function ClassRef:mapBattle()
	if self._myActor then
		self._myActor:showLocationX(self._battlePosX)
		MapManager:setFocusCharacterForInit({character=self._myActor})
	end
end

return ClassRef
